﻿' A connector consists of two nodes and a connection type. A connection has a
' filtered state. The opacity is reduced when drawing a connection that is 
' filtered. An animation is applied to the brush when the filtered state changes.

Imports System
Imports System.Windows
Imports System.Windows.Media
Imports System.Windows.Media.Animation
Imports System.Globalization

Public Class DiagramConnector

    ' Filtered settings.
    Public Const OpacityFiltered As Double = 0.15
    Public Const OpacityNormal As Double = 1.0
    Public Const AnimationDuration As Double = 300

#Region " fields "

    ' The two nodes that are connected.
    Private m_start As DiagramConnectorNode
    Private m_end As DiagramConnectorNode

    ' Flag, if the connection is currently filtered. The
    ' connection is drawn in a dim-state when filtered.
    Private m_isFiltered As Boolean

    ' Animation if the filtered state has changed.
    Private m_animation As DoubleAnimation

    ' Pen to draw connector line.
    Private m_resourcePen As Pen

#End Region

#Region " Properties "

    ''' <summary>
    ''' Return true if this is a child connector.
    ''' </summary>
    Public ReadOnly Property IsChildConnector() As Boolean
        Get
            Return True
        End Get
    End Property

    ''' <summary>
    ''' Get the starting node.
    ''' </summary>
    Protected ReadOnly Property StartNode() As DiagramConnectorNode
        Get
            Return m_start
        End Get
    End Property

    ''' <summary>
    ''' Get the ending node.
    ''' </summary>
    Protected ReadOnly Property EndNode() As DiagramConnectorNode
        Get
            Return m_end
        End Get
    End Property


    ''' <summary>
    ''' Get or set the pen that specifies the connector line.
    ''' </summary>
    Protected Property ResourcePen() As Pen
        Get
            Return m_resourcePen
        End Get
        Set(ByVal value As Pen)
            m_resourcePen = value
        End Set
    End Property

    ''' <summary>
    ''' Create the connector line pen. The opacity is set based on
    ''' the current filtered state. The pen contains an animation
    ''' if the filtered state has changed.
    ''' </summary>
    Protected ReadOnly Property Pen() As Pen
        Get
            ' Make a copy of the resource pen so it can 
            ' be modified, the resource pen is frozen.
            Dim connectorPen As Pen = Me.ResourcePen.Clone()

            ' Set opacity based on the filtered state.
            connectorPen.Brush.Opacity = CDbl(IIf(Me.IsFiltered, OpacityFiltered, OpacityNormal))

            ' Create animation if the filtered state has changed.
            If Not m_animation Is Nothing Then
                connectorPen.Brush.BeginAnimation(Brush.OpacityProperty, m_animation)
            End If
            Return connectorPen
        End Get
    End Property

    ''' <summary>
    ''' Return true if the connection is currently filtered.
    ''' </summary>
    Private Property IsFiltered() As Boolean
        Get
            Return m_isFiltered
        End Get
        Set(ByVal value As Boolean)
            m_isFiltered = value
        End Set
    End Property

    ''' <summary>
    ''' Get the new filtered state of the connection. This depends
    ''' on the connection nodes, marriage date and previous marriage date.
    ''' </summary>
    Protected ReadOnly Property NewFilteredState() As Boolean
        Get
            ' Connection is filtered if any of the nodes are filtered.
            If m_start.Node.IsFiltered OrElse m_end.Node.IsFiltered Then
                Return True
            End If
            ' Connection is not filtered.
            Return False
        End Get
    End Property


#End Region

    ''' <summary>
    ''' Consturctor that specifies the two nodes that are connected.
    ''' </summary>
    Protected Sub New(ByVal startConnector As DiagramConnectorNode, ByVal endConnector As DiagramConnectorNode)
        Me.m_start = startConnector
        Me.m_end = endConnector
    End Sub


    ''' <summary>
    ''' Return true if should continue drawing, otherwise false.
    ''' </summary>
    Public Overridable Function Draw(ByVal drawingContext As DrawingContext) As Boolean
        ' Don't draw if either of the nodes are filtered.
        If Not m_start.Node.Visibility = Visibility.Visible And Not m_end.Node.Visibility = Visibility.Visible Then
            Return False
        End If
        ' First check if the filtered state has changed, an animation
        ' if created if the state has changed which is used for all 
        ' connection drawing.
        CheckIfFilteredChanged()
        Return True
    End Function

    ''' <summary>
    ''' Create the specified brush. The opacity is set based on the 
    ''' current filtered state. The brush contains an animation if 
    ''' the filtered state has changed.
    ''' </summary>
    Protected Function GetBrush(ByVal Color As Color) As SolidColorBrush
        ' Create the brush.
        Dim brush As New SolidColorBrush(Color)
        ' Set the opacity based on the filtered state.
        brush.Opacity = CDbl(IIf(Me.m_isFiltered, OpacityFiltered, OpacityNormal))
        ' Create animation if the filtered state has changed.
        If Not m_animation Is Nothing Then
            brush.BeginAnimation(Windows.Media.Brush.OpacityProperty, m_animation)
        End If
        Return brush
    End Function

    ''' <summary>
    ''' Determine if the filtered state has changed, and create
    ''' the animation that is used to draw the connection.
    ''' </summary>
    Protected Sub CheckIfFilteredChanged()
        ' See if the filtered state has changed.
        Dim newFiltered As Boolean = Me.NewFilteredState
        If Not newFiltered = Me.m_isFiltered Then
            ' Filtered state did change, create the animation.
            Me.m_isFiltered = newFiltered
            m_animation = New DoubleAnimation()
            m_animation.From = CType(IIf(m_isFiltered, OpacityNormal, OpacityFiltered), Double?)
            m_animation.To = CType(IIf(m_isFiltered, OpacityFiltered, OpacityNormal), Double?)
            m_animation.Duration = Helper.GetAnimationDuration(AnimationDuration)
        Else
            'Filtered state did not change, clear the animation.
            m_animation = Nothing
        End If

    End Sub


End Class
